#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <algorithm> 
#include <vector>
#include <inttypes.h>

#include "libsecurity.h"
#include "r5.h"

#define TEST_OBJECT_SIZE	7000

void cout_hex(char *addr, uint32_t len)
{
    if(addr == nullptr)
        return;
    for(uint32_t i = 0; i < len; i++) {
        printf("%02x", addr[i]);
    }
    std::cout << std::endl;
}

static void print_hex(const char *info,unsigned char*data,unsigned int len){
    printf("%s[len:%d | 0x%x]\n",info,len,len);
    for(int i=0;i<len;i++){
        printf("%02x ",data[i]);
    }
    printf("\n");
}

/* Func: show_libsec_HD_RAND_bytes
 *
 * SHOW:
 *   - libsec_HD_RAND_bytes: used to generating a hardware random numb
 */
void show_libsec_HD_RAND_bytes()
{
    int ret = 0;

    unsigned char buf[4] = {"0"};
    unsigned int num = 4;

    printf("\n-----\nSHOW libsec_HD_RAND_bytes():\n");
    printf("INPUT: buf=%s num=%d\n", buf, num);

    ret = libsec_HD_RAND_bytes(buf, num);

    printf("OUTPUT: ret=%d buf=0x", ret);
    for(unsigned int i = 0; i < num; i++) {
        printf("%02x", buf[i]);
    }
    printf("\n");
}

/* Func: show_libsec_R5_CRC
 *
 * SHOW:
 *   - libsec_R5_CRC_ex: used to hardware CRC32 calculation
 *   - libsec_R5_CRC32: used to hardware CRC32 calculation, equivalent to libsec_R5_CRC_ex(data,dataLen,0,0,0,0,crc)
 */
void show_libsec_R5_CRC()
{
    int ret = 0;

    unsigned char data[] = "abc123";
    unsigned int dataLen = 6;
    unsigned int mode = 0; // crc32
    unsigned int initData = 0; // 0x0000
    unsigned int refData = 0; // ref
    unsigned int xorData = 0; // 0x0000
    unsigned int crc, crc32;

    // libsec_R5_CRC_ex
    printf("\n-----\nSHOW libsec_R5_CRC_ex():\n");
    printf("INPUT: data=%s dataLen=%d mode=%d initData=%d refData=%d xorData=%d crc=0x%04x\n", data, dataLen, mode, initData, refData, xorData, crc);

    ret = libsec_R5_CRC_ex(data, dataLen, mode, initData, refData, xorData, &crc);

    printf("OUTPUT: ret=%d crc=0x%04x\n", ret, crc);

    // libsec_R5_CRC32
    printf("\n-----\nSHOW libsec_R5_CRC32():\n");
    printf("INPUT: data=%s dataLen=%d crc32=0x%04x\n", data, dataLen, crc32);

    ret = libsec_R5_CRC32(data, dataLen, &crc32);

    printf("OUTPUT: ret=%d crc32=0x%04x\n", ret, crc32);
}

/* Func: show_libsec_R5_hash
 *
 * SHOW:
 *   - libsec_R5_hash: used to R5 hash operation
 *   - libsec_R5_file_hash: used to R5 file hash operation
 */
void show_libsec_R5_hash()
{
    int ret = 0;

    unsigned char data[] = "abc123";
    unsigned int dataLen = 6;
    unsigned int mode = 2; // SHA256
    unsigned char hash[100] = {0};
    unsigned int hashLen = 100;

    // libsec_R5_hash
    printf("\n-----\nSHOW libsec_R5_hash():\n");
    printf("INPUT: data=%s dataLen=%d mode=%d hash=%s hashLen=%d\n", data, dataLen, mode, hash, hashLen);

    ret = libsec_R5_hash(data, dataLen, mode, hash, (unsigned int*) &hashLen);

    printf("OUTPUT: ret=%d hash=0x", ret);
    for(unsigned int i = 0; i < hashLen; i++) {
        printf("%02x", hash[i]);
    }
    printf(" hashLen=%d\n", hashLen);

    // libsec_R5_file_hash
    printf("\n-----\nSHOW libsec_R5_file_hash():\n");

    // Construct a file
    FILE *fp;
    char filename[] = "api_test.txt";
    if((fp = fopen(filename, "w+")) == NULL)
    {
        printf("ERROR: open api_test.txt\n");
        return;
    }
    fputs(reinterpret_cast<const char *>(data), fp);
    fclose(fp);
    
    printf("INPUT: filename=%s mode=%d hash=%s hashLen=%d\n", filename, mode, hash, hashLen);

    ret = libsec_R5_file_hash(filename, mode, hash, (unsigned int*) &hashLen);

    printf("OUTPUT: ret=%d hash=0x", ret);
    for(unsigned int i = 0; i < hashLen; i++) {
        printf("%02x", hash[i]);
    }
    printf(" hashLen=%d\n", hashLen);
    remove(filename);
}

/* Func: show_libsec_r5_HMAC
 *
 * SHOW:
 *   - libsec_r5_HMAC: used to calculate HMAC value
 */
void show_libsec_r5_HMAC()
{
    int ret = 0;

    unsigned char data[] = "abc123";
    unsigned int data_len = 6;
    E_MSHA_MODE mode; // SHA256
    unsigned char key[] = "xyz";
    unsigned int key_len = 3;
    SEC_KEYMODE key_type; // Encrypt with the passed-in key
    const int key_idx = 0; 
    unsigned char *data_out;
    unsigned int data_out_len;

    // libsec_r5_HMAC
    printf("\n-----\nSHOW libsec_r5_HMAC():\n");

    data_out = (unsigned char*)malloc(key_len);
    memset(data_out, 0, sizeof(int)*key_len);
    data_out_len = key_len;
    key_type = SEC_KEYMODE_NORMAL;
    mode = MSHA_HMAC256; 

    printf("INPUT: data=%s data_len=%d key=%s key_len=%d mode=%d key_type=%d key_idx=%d data_out=%s data_out_len=%d\n", data, data_len, key, key_len, mode, key_type, key_idx, data_out, data_out_len);

    ret = libsec_r5_HMAC(data, data_len, key, key_len, mode, key_type, key_idx, data_out, &data_out_len);

    printf("OUTPUT: ret=%d data_out=0x", ret);
    for(unsigned int i = 0; i < data_out_len; i++) {
        printf("%02x", data_out[i]);
    }
    printf(" data_out_len=%d\n", data_out_len);
}



/* Func: show_libsec_R5_RSA_EDN
 *
 * SHOW:
 *   - libsec_R5_RSA_EDN: used to encrypt and decrypt R5 RSA according to EDN value
 */
void show_libsec_R5_RSA_EDN()
{
    int ret = 0;

    unsigned char data[64] = "abc123";
    unsigned int dataLen = 64;
    unsigned int keyLen = 64;
    unsigned int modLen = 64;
    unsigned char out1[64] = {0}; // Encrypt result
    unsigned char out2[64] = {0}; // Decrypt result
    int outLen = 64;

    // libsec_R5_RSA_EDN
    printf("\n-----\nSHOW libsec_R5_RSA_EDN():\n");

    // Encrypt key1
    unsigned char E512[64] = {0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    // Decrypt key2
    unsigned char D512[64] = {0xf1, 0x48, 0xf4, 0xd1, 0xad, 0xf6, 0x4e, 0xf3, 0x78, 0x7f, 0x0a, 0x47, 0x41, 0x22, 0xdf, 0x96, 0x91, 0xd5, 0x00, 0x07, 0x6c, 0x26, 0xbd, 0x47, 0xbc, 0x2d, 0x61, 0x0b, 0xf8, 0xf4, 0x4a, 0x19, 0x56, 0xf7, 0x01, 0x57, 0x92, 0xb4, 0x07, 0xee, 0x2b, 0xf5, 0x37, 0x28, 0x0a, 0x30, 0x7b, 0xb9, 0xc2, 0x5c, 0x28, 0x90, 0x71, 0xd0, 0x79, 0x2d, 0x91, 0xac, 0xb4, 0x9a, 0x28, 0x06, 0xf4, 0x02};

    // mod
    unsigned char N512[64] = {0x29, 0xb6, 0xa5, 0x38, 0xa2, 0x73, 0x4c, 0xb5, 0xa6, 0x8c, 0x88, 0x4e, 0x68, 0xa8, 0x01, 0xda, 0xaf, 0xd1, 0x2e, 0x79, 0x89, 0x05, 0xc8, 0xa2, 0xc4, 0x86, 0xfe, 0x6a, 0xbc, 0xe8, 0xe3, 0x20, 0xad, 0xb2, 0x51, 0xba, 0x15, 0xd0, 0xbb, 0x4d, 0x74, 0x4f, 0x13, 0x94, 0xbe, 0xf3, 0x8e, 0x69, 0x07, 0x41, 0x6f, 0xa8, 0xcc, 0x0e, 0x3b, 0xa3, 0xfd, 0x3b, 0x7f, 0xc9, 0xd4, 0xe0, 0x5f, 0xb3};

    printf("INPUT: data=%s dataLen=%d out1=%s\n", data, dataLen, out1);

    // Encrypt
    ret = libsec_R5_RSA_EDN(data, dataLen, E512, keyLen, N512, modLen, out1, &outLen);

    printf("OUTPUT: ret=%d out1=0x", ret);
    for(int i = 0; i < outLen; i++) {
        printf("%02x", out1[i]);
    }
    printf(" outLen=%d\n", outLen);

    // Decrypt
    ret = libsec_R5_RSA_EDN(out1, outLen, D512, keyLen, N512, modLen, out2, &outLen);

    printf("OUTPUT: ret=%d out2=%s outLen=%d\n", ret, out2, outLen);
}

/* Func: show_libsec_R5_GetTmpEncryptedAESKey_OTPWriteEncryptedKey
 *
 * SHOW:
 *   - libsec_R5_GetTmpEncryptedAESKey: used to R5 to obtain temporary AES key encrypted by public key (OTP encryption burning step 1)
 *   - libsec_R5_OTPWriteEncryptedKey: used to R5 to burn AES encrypted key(OTP encryption burning step 2)
 */
void show_libsec_R5_GetTmpEncryptedAESKey_OTPWriteEncryptedKey()
{
    int ret = 0;

    unsigned char pub[294]= {0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xea, 0x2a, 0x8f, 0x3a, 0x54, 0x8d, 0x48, 0x34, 0x14, 0xa3, 0x80, 0xde, 0x9f, 0xeb, 0x3e, 0xc9, 0x7f, 0x68, 0x1c, 0x32, 0xfc, 0xbb, 0x9b, 0xa5, 0xec, 0xf7, 0xa9, 0x8f, 0x08, 0x5f, 0xef, 0xb5, 0x8a, 0x42, 0xbd, 0xe4, 0xcc, 0xb7, 0xa6, 0x49, 0x19, 0xc6, 0x4e, 0xa5, 0x79, 0x16, 0x3b, 0x5d, 0xfa, 0xdd, 0x77, 0x3f, 0xf5, 0x86, 0xd2, 0x0e, 0xd0, 0x8e, 0x57, 0x39, 0x0b, 0xc0, 0x8e, 0x03, 0x51, 0xc3, 0x26, 0x4c, 0x1a, 0xf3, 0x61, 0xbe, 0xf9, 0xe8, 0xc0, 0x61, 0xc1, 0x9f, 0x4c, 0xb7, 0x62, 0x45, 0x5a, 0x95, 0xe3, 0xd4, 0xf0, 0x06, 0x62, 0x8f, 0x73, 0x61, 0x57, 0xca, 0x56, 0xc3, 0x14, 0x0f, 0xc1, 0x56, 0x42, 0xd7, 0x6d, 0xdb, 0xf2, 0xc9, 0xad, 0xbf, 0x34, 0x8d, 0x90, 0xea, 0x59, 0x21, 0x69, 0xce, 0x96, 0x0d, 0x20, 0x55, 0xb8, 0xbe, 0x2d, 0xed, 0x45, 0xe7, 0xee, 0xec, 0x45, 0xb6, 0x2d, 0x03, 0x3d, 0x5d, 0x39, 0x16, 0xb4, 0xa5, 0x98, 0xed, 0x40, 0xa2, 0x58, 0xc5, 0xb1, 0xf8, 0xa8, 0xe8, 0xf7, 0x6e, 0xcd, 0xb6, 0x71, 0x83, 0xae, 0xf8, 0x32, 0xee, 0x03, 0xa1, 0xeb, 0x35, 0x3f, 0x77, 0x8b, 0x35, 0x76, 0x35, 0x81, 0xfe, 0xb3, 0xf1, 0xd9, 0xc1, 0xe9, 0x17, 0x84, 0xec, 0xcd, 0x6e, 0xdd, 0x9b, 0xa3, 0xfc, 0x58, 0x61, 0xe4, 0xa0, 0xd7, 0x02, 0x6c, 0xf3, 0x88, 0x24, 0x7d, 0xec, 0xff, 0xc4, 0x57, 0x38, 0xfd, 0xcc, 0x21, 0x59, 0x47, 0x31, 0x87, 0x3e, 0x25, 0xf3, 0xe8, 0x1c, 0xc2, 0xdd, 0x8f, 0xe6, 0xa2, 0x36, 0xed, 0x0c, 0xc6, 0x51, 0xc6, 0x85, 0x1c, 0x06, 0x98, 0xe9, 0xb5, 0xab, 0x83, 0x58, 0xf2, 0x07, 0x9d, 0x5a, 0xa9, 0x41, 0xb1, 0x09, 0x83, 0x5c, 0x33, 0xdc, 0x49, 0x40, 0xdc, 0xd3, 0x19, 0x28, 0x7b, 0xbd, 0xfd, 0x98, 0x78, 0x43, 0x02, 0x03, 0x01, 0x00, 0x01};
    unsigned int pubLen = sizeof(pub);
    unsigned int keyID = 0xabcd0005; // SBR_AES_KEY = 0xabcd0005
    unsigned char key[256] = {0};
    unsigned int keyLen = 256;

    // libsec_R5_GetTmpEncryptedAESKey
    printf("\n-----\nSHOW libsec_R5_GetTmpEncryptedAESKey():\n");

    printf("INPUT: pub=... pubLen=%d key=%s keyLen=%d keyID=%d\n", pubLen, key, keyLen, keyID);

    ret = libsec_R5_GetTmpEncryptedAESKey(pub, pubLen, key, &keyLen);

    printf("OUTPUT: ret=%d key=0x", ret);
    for(unsigned int i = 0; i < keyLen; i++) {
        printf("%02x", key[i]);
    }
    printf(" keyLen=%d\n", keyLen);

    // libsec_R5_OTPWriteEncryptedKey
    printf("\n-----\nSHOW libsec_R5_OTPWriteEncryptedKey():\n");

    printf("INPUT: keyID=%d(0xabcd0005/SBR_AES_KEY)\n", keyID);

    // libsec_R5_OTPWriteEncryptedKey(Set related non-test calls, and use them as needed)
    //ret = libsec_R5_OTPWriteEncryptedKey(keyID, key, keyLen);

    printf("OUTPUT: ret=%d\n", ret);
}

/* Func: show_libsec_R5_SM
 *
 * SHOW:
 *   - libsec_R5_SM3: used to R5 secret SM3 operation
 *   - libsec_R5_SM4: used to R5 secret SM4 operation
 */
void show_libsec_R5_SM()
{
    int ret = 0;

    unsigned char data3[64] = "abc123";
    unsigned int dataLen3 = 64;
    unsigned char out3[64] = {0}; // SM3
    unsigned int outLen3 = 64;

    unsigned char data4[16] = "abcdefgh1234567";
    unsigned int dataLen4 = 16;
    unsigned char out4E[16] = {0}; // SM4 encrypt
    unsigned char out4D[16] = {0}; // SM4 decrypt
    unsigned int outLen4 = 16;
    int mode = 0; // SM4_ECB
    int useUserKey = 0; // Do not use user key
    unsigned char key[16] = "miyaokey1234567";
    unsigned int keyLen = 16;
    int isEnc = 1; // encrypt
    unsigned char ivec[16] = "ivecivec1234567";
    unsigned int ivecLen = 16;

    // libsec_R5_SM3
    printf("\n-----\nSHOW libsec_R5_SM3():\n");

    printf("INPUT: data3=%s dataLen3=%d out3=%s outLen3=%d\n", data3, dataLen3, out3, outLen3);

    ret = libsec_R5_SM3(data3, dataLen3, out3, (unsigned int*)&outLen3);

    printf("OUTPUT: ret=%d out3=0x", ret);
    for(unsigned int i = 0; i < outLen3; i++) {
        printf("%02x", out3[i]);
    }
    printf(" outLen3=%d\n", outLen3);

    // libsec_R5_SM4
    printf("\n-----\nSHOW libsec_R5_SM4():\n");

    printf("INPUT: data4=%s dataLen4=%d mode=%d useUserKey=%d key=%s keyLen=%d isEnc=%d ivec=%s ivecLen=%d out4E=%s outLen4=%d\n", data4, dataLen4, mode, useUserKey, key, keyLen, isEnc, ivec, ivecLen, out4E, outLen4);

    ret = libsec_R5_SM4(data4, dataLen4, mode, useUserKey, key, keyLen, ivec, ivecLen, isEnc, out4E, outLen4);

    printf("OUTPUT: ret=%d out4E=0x", ret);
    for(unsigned int i = 0; i < outLen4; i++) {
        printf("%02x", out4E[i]);
    }
    printf(" outLen4=%d\n", outLen4);

    // decrypt
    isEnc = 0;

    ret = libsec_R5_SM4(out4E, outLen4, mode, useUserKey, key, keyLen, ivec, ivecLen, isEnc, out4D, outLen4);

    printf("OUTPUT: ret=%d out4D=%s\n", ret, out4D);
}

/* Func: show_libsec_R5_GetLifeStage_SetLifeStage
 *
 * SHOW:
 *   - libsec_R5_GetLifeStage: used for R5 to get the current life cycle state of the chip
 *   - libsec_R5_SetLifeStage: used for R5 to set the current life cycle state of the chip
 *
 * NOTE:
 *   - There is terminal printing in the function
 */
void show_libsec_R5_GetLifeStage_SetLifeStage()
{
    int ret = 0;
    unsigned int lifeStage = 0; // NULL

    // libsec_R5_GetLifeStage
    printf("\n-----\nSHOW libsec_R5_GetLifeStage():\n");

    printf("INPUT: lifeStage=%d\n", lifeStage);

    ret = libsec_R5_GetLifeStage(&lifeStage);

    printf("OUTPUT: ret=%d lifeStage=0x%x", ret, lifeStage);

    // libsec_R5_SetLifeStage
    printf("\n-----\nSHOW libsec_R5_SetLifeStage():\n");

    lifeStage = 0x24680004; // STAGE_END
    printf("INPUT: lifeStage=%d\n", lifeStage);

    // libsec_R5_SetLifeStage(Set related non-test calls, and use them as needed)
    //ret = libsec_R5_SetLifeStage(lifeStage);

    printf("OUTPUT: ret=%d lifeStage=0x%x\n", ret, lifeStage);
}

/* Func: show_libsec_r5_SetUserKey
 *
 * SHOW:
 *   - libsec_r5_SetUserKey: used to set the user key in R5 SRAM
 */
void show_libsec_r5_SetUserKey()
{
    int ret = 0;
    unsigned int keyId = 0x12340002;
    unsigned char key[16] = "miyaokey1234567";
    unsigned int keyLen = 16;

    // libsec_r5_SetUserKey
    printf("\n-----\nSHOW libsec_r5_SetUserKey():\n");

    // The user key is derived from R5
    keyId = 0x12340002;
    printf("INPUT: keyId=%x key=%s keyLen=%d\n", keyId, key, keyLen);

    ret = libsec_r5_SetUserKey(keyId, key, keyLen);

    printf("OUTPUT: ret=%d\n", ret);
}

/* Func: show_libsec_r5_SetUesrKeyFlag
 *
 * SHOW:
 *   - libsec_r5_SetUesrKeyFlag: used to set the keyFlag flag, and use the last 128bit of the user root key key to encrypt and decrypt the user key
 */
void show_libsec_r5_SetUesrKeyFlag()
{
    int ret = 0;

    // libsec_r5_SetUesrKeyFlag
    printf("\n-----\nSHOW libsec_r5_SetUesrKeyFlag():\n");

    ret = libsec_r5_SetUesrKeyFlag();

    printf("OUTPUT: ret=%d\n", ret);
}

/* Func: show_libsec_r5_EnableOtpKey
 *
 * SHOW:
 *   - libsec_r5_EnableOtpKey: used to set the Force OTP Key flag, and start the SBL sign-checking function safely
 */
void show_libsec_r5_EnableOtpKey()
{
    int ret = 0;

    // libsec_r5_EnableOtpKey
    printf("\n-----\nSHOW libsec_r5_EnableOtpKey():\n");

    ret = libsec_r5_EnableOtpKey();

    printf("OUTPUT: ret=%d\n", ret);
}

/* Func: show_libsec_r5_GetKeyStatus
 *
 * SHOW:
 *   - libsec_r5_GetKeyStatus: used to obtain the key burning status
 */
void show_libsec_r5_GetKeyStatus()
{
    int ret = 0;
    unsigned int keyId = 0xabcd0001; // User Root Key

    // libsec_r5_GetKeyStatus
    printf("\n-----\nSHOW libsec_r5_GetKeyStatus():\n");

    printf("INPUT: keyId=%x\n", keyId);

    ret = libsec_r5_GetKeyStatus(keyId);

    printf("OUTPUT: ret=%d\n", ret);
}

/* Func: show_libsec_r5_GetChipid
 *
 * SHOW:
 *   - libsec_r5_GetChipid: used to get Chipid
 */
void show_libsec_r5_GetChipid()
{
    int ret = 0;
    uint64_t id[2] = {0};

    // libsec_r5_GetChipid
    printf("\n-----\nSHOW libsec_r5_GetChipid():\n");

    ret = libsec_r5_GetChipid(id);

    printf("OUTPUT: ret=%d\n", ret);
}

/* Func: show_libsec_r5_AES_encrypt
 *
 * SHOW:
 *   - libsec_r5_AES_encrypt: used to encrypt and decrypt interface for AES R5
 */
void show_libsec_r5_AES_encrypt()
{
    int ret = 0;
    SEC_AES_MODE mode = SEC_AES_ECB; // ECB
    SEC_AES_TYPE enc = SEC_AES_ENCRYPT; // Encrypt
    unsigned char data[16] = "abcdefgh1234567";
    unsigned int dataLen = 16;
    SEC_AES_KEYLEN keyLen = SEC_AES_128_BIT; // 16byte
    SEC_KEYMODE keyMode = SEC_KEYMODE_R5SRAM; // Only the user key of R5 SRAM is supported for encryption and decryption, and the value is 1
    unsigned int keyIdx = 0x12340002; // Set libsec_r5_SetUserKey first
    unsigned char dataOut[16] = {0};
    unsigned int dataOutLen = 16;
    unsigned char ivec[16] = "ivecivec1234567";
    unsigned int ivecLen = 16;

    // libsec_r5_AES_encrypt
    printf("\n-----\nSHOW libsec_r5_AES_encrypt():\n");

    printf("INPUT: mode=%d enc=%d data=%s dataLen=%d keyLen=%d keyMode=%d keyIdx=%x dataOut=%s dataOutLen=%d\n", mode, enc, data, dataLen, keyLen, keyMode, keyIdx, dataOut, dataOutLen);

    ret = libsec_r5_AES_encrypt(mode, enc, data, dataLen, keyLen, keyMode, keyIdx, ivec, ivecLen, dataOut, &dataOutLen);

    printf("OUTPUT: ret=%d dataOut=0x", ret);
    for(unsigned int i = 0; i < dataOutLen; i++) {
        printf("%02x", dataOut[i]);
    }
    printf(" dataOutLen=%d\n", dataOutLen);
}

/* Func: show_libsec_R5_ECC_Sign_Verify
 *
 * SHOW:
 *   - libsec_R5_EccSign: for R5 Ecc Sign operation
 *   - libsec_R5_EccVerify: for R5 Ecc verify operation
 */
void show_libsec_R5_ECC_Sign_Verify()
{
    //prime256v1
    unsigned char eccPri[32] = {
        0x3d,0x46,0x5f,0x44,0x59,0x3a,0x7b,0xe5,0x0d,0x97,0x36,0x9e,0x3d,0xe6,0x82,
        0x85,0xdf,0x67,0x59,0x84,0xc5,0xb5,0xda,0xfc,0x44,0x71,0x20,0x1e,0x84,0xe2,
        0xf3,0xf2
    };
    
    unsigned char eccPubX[32] = {
        0xb1,0xd5,0x56,0x87,0x60,0x72,0x94,0xdb,0x51,0xd9,0xa4,0x6b,0x42,0xab,0x44,
        0x3b,0x22,0xbe,0x30,0x24,0xe7,0xfc,0x98,0xf9,0x36,0xc8,0x3d,0x11,0x0d,0x06,
        0xdc,0xb7
    };

    unsigned char eccPubY[32] = {
        0x89,0x16,0x79,0xe3,0x0f,0x67,0x38,0xa3,0xf5,0x1f,0x84,0x97,0x8d,0x10,0xe4,
        0xf6,0xf1,0x66,0xb0,0x77,0xa5,0x8f,0xce,0x6d,0x9c,0xb6,0x05,0x36,0x28,0x6e,
        0x5c,0x0c
    };

    unsigned char r[32],s[32];
    unsigned int rLen = 32, sLen = 32;
    unsigned char data[] = "abcdefghijklmn-000111222";
    unsigned char *tmpEccPri = eccPri;
    unsigned char *tmpEccPubX = eccPubX;
    unsigned char *tmpEccPubY = eccPubY;
    unsigned int dataLen = sizeof(data);
    int ret,useDefaultKey = 1;

    unsigned int tmpLenPri = sizeof(eccPri);
    unsigned int tmpLenPubx = sizeof(eccPubX);
    unsigned int tmpLenPuby = sizeof(eccPubY);


    printf("\n-----\nSHOW libsec_R5_EccSign():\n");
    printf("INPUT: data=%s,dataLen=%d\n",(char*)data,dataLen);
    ret = libsec_R5_EccSign(data,dataLen,0,tmpEccPri,tmpLenPri,r,&rLen,s,&sLen);

    printf("OUTPUT: ret=%d", ret);
    if(ret != SEC_SUCCESS){
        return;
    }
    print_hex("r",r,rLen);
    print_hex("s",s,sLen);

    printf("\n-----\nSHOW libsec_R5_EccVerify():\n");
    ret = libsec_R5_EccVerify(data,dataLen,0,tmpEccPubX,tmpLenPubx,tmpEccPubY,tmpLenPuby,r,rLen,s,sLen);
    printf("OUTPUT: ret=%d", ret);
}

/* Func: show_R5_GetAntiRollbackInfo
 *
 * SHOW:
 *   - libsec_R5_GetAntiRollbackInfo: for R5 get anti rollback info
 */
void show_libsec_R5_Get_AntiRollbackInfo(){
    char info[1024] = {0};
    printf("\n-----\nSHOW show_libsec_R5_Get_AntiRollbackInfo():\n");
    int ret = libsec_R5_GetAntiRollbackInfo((unsigned char *)info,sizeof(info));
    printf("OUTPUT: ret=%d", ret);
    if(ret != SEC_SUCCESS){
        return;
    }else{
        printf("GetAntiRollbackInfo success\n");
        /* if T_ROLL_BACK_INFO is defined
        T_ROLL_BACK_INFO sInfo;
        memcpy(&sInfo,info,sizeof(sInfo));
        print_hex("info",(unsigned char*)info,sizeof(T_ROLL_BACK_INFO));
        // print_hexu32("info",(unsigned int*)&sInfo,sizeof(T_ROLL_BACK_INFO)/sizeof(int));  
        printf("sInfo.enableRollBack = %08x\n",sInfo.enableRollBack);
        printf("sInfo.rollBackSoftVal_safety = %08x\n",sInfo.rollBackSoftVal_safety);
        printf("sInfo.rollBackSoftVal_A55 = %08x\n",sInfo.rollBackSoftVal_A55);
        printf("sInfo.needUpdate = %08x\n",sInfo.needUpdate);
        printf("sInfo.eCryptoType = %08x\n",sInfo.eCryptoType);
        printf("sInfo.otpKeyFlag = %08x\n",sInfo.otpKeyFlag);
        print_hexu32("sInfo.rollBackVal_OTP",sInfo.rollBackVal_OTP,sizeof(sInfo.rollBackVal_OTP)/sizeof(int));
        print_hexu32("sInfo.pubKey",sInfo.pubKey,sizeof(sInfo.pubKey)/sizeof(int));
        print_hexu32("sInfo.sign",sInfo.sign,sizeof(sInfo.sign)/sizeof(int));
        */
    }
}

/* Func: show_libsec_AES_Encrypt
 *
 * SHOW:
 *   - libsec_AES_Encrypt: used to universal interface for AES encrypt and decrypt
 */
void show_libsec_AES_Encrypt()
{
    int ret = 0;
    int cyberModule = CYBER_MODULE_R5; // R5
    SEC_AES_MODE mode = SEC_AES_CBC; // CBC
    SEC_AES_TYPE enc = SEC_AES_ENCRYPT; // encrypt
    unsigned char data[16] = "abcdefgh1234567";
    unsigned int dataLen = 16;
    unsigned char key[16] = "miyaokey1234567";
    SEC_AES_KEYLEN keyLen = SEC_AES_128_BIT; // 16byte
    unsigned char ivec[16] = "ivecivec1234567";
    unsigned int ivecLen = 16;
    unsigned char dataOutE[16] = {0};
    unsigned char dataOutD[16] = {0};
    unsigned int dataOutLen = 16;

    // libsec_AES_Encrypt
    printf("\n-----\nSHOW libsec_AES_Encrypt():\n");

    // Encrypt
    printf("INPUT: cyberModule=%d mode=%d enc=%d data=%s dataLen=%d key=%s keyLen=%d ivec=%s ivecLen=%d dataOutE=%s dataOutLen=%d\n", cyberModule, mode, enc, data, dataLen, key, keyLen, ivec, ivecLen, dataOutE, dataOutLen);

    ret = libsec_AES_Encrypt(cyberModule, mode, enc, data, dataLen, key, keyLen, ivec, ivecLen, dataOutE, &dataOutLen);

    printf("OUTPUT: ret=%d dataOutE=0x", ret);
    for(unsigned int i = 0; i < dataOutLen; i++) {
        printf("%02x", dataOutE[i]);
    }
    printf(" dataOutLen=%d\n", dataOutLen);

    // Decrypt
    enc = SEC_AES_DECRYPT;
    
    printf("INPUT: cyberModule=%d mode=%d enc=%d dataOutE=... dataOutLen=%d key=%s keyLen=%d ivec=%s ivecLen=%d dataOutD=%s dataOutLen=%d\n", cyberModule, mode, enc, dataOutLen, key, keyLen, ivec, ivecLen, dataOutD, dataOutLen);

    ret = libsec_AES_Encrypt(cyberModule, mode, enc, dataOutE, dataOutLen, key, keyLen, ivec, ivecLen, dataOutD, &dataOutLen);

    printf("OUTPUT: ret=%d dataOutD=%s\n", ret, dataOutD);
}


/* Func: show_libsec_inquire_version
 *
 * SHOW:
 *   - libsec_inquire_version: Used to query optee version information
 */
void show_libsec_inquire_version(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    struct ver_info_args ver_info_data;
    uint32_t data_len_loc = sizeof(ver_info_data);

    printf("\n-----\nSHOW libsec_inquire_version():\n");
    res = libsec_inquire_version(&ver_info_data, &data_len_loc);
    printf("OUTPUT: ret=%d\n", res);
    switch(res) {
        case SEC_SUCCESS:
            printf("inquire the version success\n");
            std::cout << "version result:" << std::endl;
            std::cout << ver_info_data.a0 << "." << ver_info_data.a1 << "." << ver_info_data.a2 << std::endl;
            break;
        case SEC_ITEM_NOT_FOUND:
            printf("version not found in TEE.\n");
            break;
        default:
            printf("Failed to inquire version. Ret:%x\n", res);
            break;
    };
}

/* Func: show_libsec_storage_read_data
 *
 * SHOW:
 *   - libsec_storage_read_data: Used to read securely stored data
 */
void show_libsec_storage_read_data(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    std::string obj_id_str = "abc";

    char id[obj_id_str.length() + 1] = {0};
    obj_id_str.copy(id, obj_id_str.length(), 0);

    uint32_t data_len = 6;
    uint32_t data_len_loc = TEST_OBJECT_SIZE;

	char read_data[TEST_OBJECT_SIZE];
    printf("\n-----\nSHOW libsec_storage_read_data():\n");
    printf("INPUT: id=%s data_len_loc=%d\n", id, data_len_loc);
	res = libsec_storage_read_data(id, read_data, &data_len_loc, STORAGE_SEC_REE);
    printf("OUTPUT: ret=%d\n", res);
    switch(res) {
        case SEC_SUCCESS:
            printf("Read the object success\n");
            std::cout << "Data(hex):" << std::endl;
            cout_hex(read_data, (data_len < data_len_loc)? data_len : data_len_loc);
            break;
        case SEC_ITEM_NOT_FOUND:
            printf("Object not found in TA secure storage.\n");
            break;
        default:
            printf("Failed to read an object from the secure storage. Ret:%x\n", res);
            break;
    };
	return;
}

/* Func: show_libsec_storage_read_data_ex
 *
 * SHOW:
 *   - libsec_storage_read_data_ex: Used to read data from an offset location in the secure storage area
 */
void show_libsec_storage_read_data_ex(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    int offset = 3;
    std::string obj_id_str = "abc";

    char id[obj_id_str.length() + 1] = {0};
    obj_id_str.copy(id, obj_id_str.length(), 0);

    uint32_t data_len = 6;
    uint32_t data_len_loc = TEST_OBJECT_SIZE;
	char data[data_len];

    printf("\n-----\nSHOW libsec_storage_read_data_ex():\n");
    printf("INPUT: id=%s data_len=%d offset=%d\n", id, data_len, offset);
	res = libsec_storage_read_data_ex(id, data, &data_len, offset, STORAGE_SEC_REE);
    printf("OUTPUT: ret=%d\n", res);
	if (res != SEC_SUCCESS){
		std::cout << "Failed to read object in the secure storage." << std::endl;
    }
    else{
        std::cout << "Read the object success." << std::endl;
        std::cout << "data_len = "<< data_len<< ". Data(hex):" << std::endl;
        cout_hex(data, (data_len < data_len_loc)? data_len : data_len_loc);

    }

    return;
}

/* Func: show_libsec_storage_write_data
 *
 * SHOW:
 *   - libsec_storage_write_data: Used to save data to a secure storage area, with the function of creating a storage unit object
 */
void show_libsec_storage_write_data(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    std::string obj_id_str = "abc";

    char id[obj_id_str.length() + 1] = {0};
    obj_id_str.copy(id, obj_id_str.length(), 0);

    std::vector<unsigned char> obj_data = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};

    char *data = (char *)malloc(obj_data.size());
	if(data == nullptr) {
		return;
	}
    for(uint32_t i = 0; i < obj_data.size(); i++) {
        data[i] = (char)obj_data[i];
    }

    printf("\n-----\nSHOW libsec_storage_write_data():\n");
    printf("INPUT: id=%s data_len=%d\n", id, obj_data.size());
    cout_hex(data, obj_data.size());
	res = libsec_storage_write_data(id, data, obj_data.size(), STORAGE_SEC_REE);
    printf("OUTPUT: ret=%d\n", res);

    free(data);
    return;
}

/* Func: show_libsec_storage_delete_object
 *
 * SHOW:
 *   - libsec_storage_delete_object: Used to delete saved data
 */
void show_libsec_storage_delete_object(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    std::string obj_id_str = "abc";
    char id[obj_id_str.length() + 1] = {0};
    obj_id_str.copy(id, obj_id_str.length(), 0);

    printf("\n-----\nSHOW libsec_storage_delete_object():\n");
    printf("INPUT: id=%s\n", id);
    res = libsec_storage_delete_object(id, STORAGE_SEC_REE);
    printf("OUTPUT: ret=%d\n", res);

    return;
}

/* Func: show_libsec_storage_update_data
 *
 * SHOW:
 *   - libsec_storage_update_data: Used to update data to secure storage
 */
void show_libsec_storage_update_data(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    int offset = 3;
    std::string obj_id_str = "abc";

    char id[obj_id_str.length() + 1] = {0};
    obj_id_str.copy(id, obj_id_str.length(), 0);

    std::vector<unsigned char> obj_data = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
    char *data = (char *)malloc(obj_data.size());
	if(data == nullptr) {
		return;
	}
    for(uint32_t i = 0; i < obj_data.size(); i++) {
        data[i] = (char)obj_data[i];
    }

    printf("\n-----\nSHOW libsec_storage_update_data():\n");
    printf("INPUT: id=%s data_len=%d offset=%d\n", id, obj_data.size(), offset);
    cout_hex(data, obj_data.size());
	res = libsec_storage_update_data(id, data, obj_data.size(), offset, STORAGE_SEC_REE);
    printf("OUTPUT: ret=%d\n", res);

    free(data);
    return;
}

/* Func: show_libsec_storage_truncate_data
 *
 * SHOW:
 *   - libsec_storage_truncate_data: Used to intercept data from secure storage objects
 */
void show_libsec_storage_truncate_data(void) {
    int res = SEC_SUCCESS;         /* Define the return value of function */
    std::string obj_id_str = "abc";

    char id[obj_id_str.length() + 1] = {0};
    obj_id_str.copy(id, obj_id_str.length(), 0);
    uint32_t size = 5;

    printf("\n-----\nSHOW libsec_storage_truncate_data():\n");
    printf("INPUT: id=%s size=%d\n", id, size);
	res = libsec_storage_truncate_data(id, size, STORAGE_SEC_REE);
    printf("OUTPUT: ret=%d\n", res);

    return;
}

/* Func: show_Symmetry_demo
 *
 * SHOW:
 *   - Symmetry_encrypt: For symmetric encryption of data
 *   - Symmetry_decrypt: for symmetric decryption of data
 */
void show_Symmetry_demo(void){
    std::vector<unsigned char> _data = {0x37, 0x33, 0x31, 0x34, 0x35, 0x36};
    std::vector<unsigned char> _key = {0x24, 0x52, 0x31, 0x41, 0x63, 0x35, 0x22, 0x33, 0x19, 0x56, 0x54, 0x62, 0x46, 0x28, 0x45, 0x38};
    std::vector<unsigned char> _ivec = {0x45, 0x32, 0x16, 0x24, 0x42, 0x55};
    unsigned char* origin_data = (unsigned char*)malloc(DATA_MAX_LEN);
    unsigned char* key = (unsigned char*)malloc(SEC_AES_256_BIT);
    unsigned char* ivec = (unsigned char*)malloc(IVEC_LEN);
    unsigned char* encrypt_data = (unsigned char*)malloc(DATA_MAX_LEN);
    unsigned char* decrypt_data = (unsigned char*)malloc(DATA_MAX_LEN);
    uint32_t encrypt_len = 0, decrypt_len = 0;
    int enc = 0, res = SEC_SUCCESS;

    // set original data
    for(unsigned int i = 0; i < _data.size(); i++) {
        origin_data[i] = _data[i];
    }

    // set key
    for(unsigned int i = 0; i < _key.size(); i++) {
        key[i] = _key[i];
    }

    // set ivec
    for(unsigned int i = 0; i < _ivec.size(); i++) {
        ivec[i] = _ivec[i];
    }

    // Symmetry_encrypt
    encrypt_len = _data.size() + 16;
    printf("\n-----\nSHOW Symmetry_encrypt():\n");
    printf("the original data length is：%zu, data:\n\t", _data.size());
    for(unsigned int i = 1; i <= _data.size(); i++) {
        printf("%02x ", origin_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Symmetry_encrypt(origin_data, _data.size(),
                            key, _key.size(),
                            // ivec, _ivec.size(),
                            nullptr, 0,
                            encrypt_data, &encrypt_len);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe encrypted data length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // Symmetry_decrypt
    decrypt_len = encrypt_len;
    printf("\n-----\nSHOW Symmetry_decrypt():\n");
    printf("the encrypted length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Symmetry_decrypt(encrypt_data, encrypt_len,
                            key, _key.size(),
                            // ivec, _ivec.size(),
                            nullptr, 0,
                            decrypt_data, &decrypt_len);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe decrypted length is：%zu, data:\n\t", decrypt_len);
    for(unsigned int i = 1; i <= decrypt_len; i++) {
        printf("%02x ", decrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

exit:
    free(origin_data);
    free(key);
    free(ivec);
    free(encrypt_data);
    free(decrypt_data);
    return ;
}

/* Func: show_Asymmetry_RSA_demo
 *
 * SHOW:
 *   - Asymmetry_RSA_keygen: For asymmetric (RSA) key generation
 *   - Asymmetry_RSA_encrypt: For asymmetric (RSA) encrypted data
 *   - Asymmetry_RSA_decrypt: For asymmetric (RSA) decryption of data
 *   - Asymmetry_RSA_sign: For asymmetric (RSA) data signing
 *   - Asymmetry_RSA_verify: For asymmetric (RSA) data signature verification
 */
int show_Asymmetry_RSA_demo(void){
    RSA_prikey prikey;
    RSA_pubkey pubkey;
    std::vector<char> _data = {0x37, 0x33, 0x31, 0x34, 0x35, 0x36};
    size_t data_len = 0, encrypt_len = DATA_MAX_LEN, decrypt_len = DATA_MAX_LEN;
    int enc = 0, res = SEC_SUCCESS;
    size_t key_len = 0, alg_enc = 0;
    std::vector<char> v_data = {0x37, 0x33, 0x31, 0x34, 0x35, 0x36};
    // char* verify_data = ( char*)malloc(DATA_MAX_LEN);
    // size_t verify_data_len = 0;
    // unsigned char md[16] = {0};
    // unsigned char md2[16] = {0};

    pubkey.modulus  = (char*)malloc(4096);
    pubkey.pub_expo = (char*)malloc(4096);
    prikey.modulus  = (char*)malloc(4096);
    prikey.pub_expo = (char*)malloc(4096);
    prikey.pri_expo = (char*)malloc(4096);
    char* origin_data  = (char*)malloc(DATA_MAX_LEN);
    char* encrypt_data = (char*)malloc(DATA_MAX_LEN);
    char* decrypt_data = (char*)malloc(DATA_MAX_LEN);
    if( nullptr == pubkey.modulus  ||
        nullptr == pubkey.pub_expo ||
        nullptr == prikey.modulus  ||
        nullptr == prikey.pub_expo ||
        nullptr == prikey.pri_expo ||
        nullptr == origin_data     ||
        nullptr == encrypt_data    ||
        nullptr == decrypt_data){
        printf("malloc fail.\n");
        goto out;
    }

    memset(origin_data, 0, DATA_MAX_LEN);
    data_len = _data.size();
    for(unsigned int i = 0; i < data_len; i++) {
        origin_data[i] = _data[i];
    }

    key_len = 1024; // (512/768/1024/1536/2048/4096)
    memset(pubkey.modulus,  0, 4096);
    memset(pubkey.pub_expo, 0, 4096);
    memset(prikey.modulus,  0, 4096);
    memset(prikey.pub_expo, 0, 4096);
    memset(prikey.pri_expo, 0, 4096);
    prikey.modu_len = key_len / 8;
    prikey.pub_len  = 3;
    prikey.pri_len  = key_len / 8;
    pubkey.modu_len = key_len / 8;
    pubkey.pub_len  = 3;
    printf("\n-----\nSHOW Asymmetry_RSA_keygen():\n");
    printf("INPUT: key_len=%d\n", key_len);
    res = Asymmetry_RSA_keygen(key_len, pubkey, prikey);
    printf("OUTPUT: ret=%d\n", res);

    printf("prikey:\n");
    printf("modulus len = %zu, modulus:\n\t", prikey.modu_len);
    for(unsigned int i = 1; i <= prikey.modu_len; i++) {
        printf("%02x ", prikey.modulus[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\npub_expo len = %zu, pub_expo:\n\t", prikey.pub_len);
    for(unsigned int i = 1; i <= prikey.pub_len; i++) {
        printf("%02x ", prikey.pub_expo[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\npri_expo len = %zu,  pri_expo:\n\t", prikey.pri_len);
    for(unsigned int i = 1; i <= prikey.pri_len; i++) {
        printf("%02x ", prikey.pri_expo[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");
    printf("pubkey:\n");
    printf("modulus len = %zu, modulus:\n\t", pubkey.modu_len);
    for(unsigned int i = 1; i <= pubkey.modu_len; i++) {
        printf("%02x ", pubkey.modulus[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\npub_expo len = %zu, pub_expo:\n\t", pubkey.pub_len);
    for(unsigned int i = 1; i <= pubkey.pub_len; i++) {
        printf("%02x ", pubkey.pub_expo[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // encrypt, RSAES_PKCS1_OAEP_MGF1_SHA256 alorithm
    encrypt_len = DATA_MAX_LEN;
    printf("\n-----\nSHOW Asymmetry_RSA_encrypt():\n");
    printf("the original data length is：%zu, data:\n\t", data_len);
    for(unsigned int i = 1; i <= data_len; i++) {
        printf("%02x ", origin_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Asymmetry_RSA_encrypt(origin_data, data_len,
            encrypt_data, &encrypt_len,
            pubkey, key_len, RSAES_PKCS1_OAEP_MGF1_SHA256);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe encrypted data length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // decrypt RSAES_PKCS1_OAEP_MGF1_SHA256 alorithm
    decrypt_len = encrypt_len;
    printf("\n-----\nSHOW Asymmetry_RSA_decrypt():\n");
    printf("the encrypted length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Asymmetry_RSA_decrypt(encrypt_data, encrypt_len,
            decrypt_data, &decrypt_len,
            prikey, key_len, RSAES_PKCS1_OAEP_MGF1_SHA256);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe decrypted length is：%zu, data:\n\t", decrypt_len);
    for(unsigned int i = 1; i <= decrypt_len; i++) {
        printf("%02x ", decrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

#if 0
    // sign RSASSA_PKCS1_V1_5_MD5 alorithm
    liboa_MD5((unsigned char*)origin_data, data_len, md);
    for(int i = 0; i < 16; i++){
        printf("%02x", md[i]);
    }
    encrypt_len = key_len;
    printf("\n-----\nSHOW Asymmetry_RSA_sign():\n");
    printf("the original data length is：%zu, data:\n\t", data_len);
    for(unsigned int i = 1; i <= data_len; i++) {
        printf("%02x ", origin_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Asymmetry_RSA_sign((char*)md, 16,
            encrypt_data, &encrypt_len,
            prikey, key_len, RSASSA_PKCS1_V1_5_MD5);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe encrypted data length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // verify RSASSA_PKCS1_V1_5_MD5 alorithm
    memset(verify_data, 0, DATA_MAX_LEN);
    verify_data_len = v_data.size();
    for(unsigned int i = 0; i < verify_data_len; i++) {
        verify_data[i] = v_data[i];
    }
    liboa_MD5((unsigned char*)verify_data, verify_data_len, md2);
    for(int i = 0; i < 16; i++){
        printf("%02x", md2[i]);
    }
    printf("\n-----\nSHOW Asymmetry_RSA_verify():\n");
    res = Asymmetry_RSA_verify((char*)md2, 16,
            encrypt_data, encrypt_len,
            pubkey, key_len, RSASSA_PKCS1_V1_5_MD5);        //last param may be wrong
    printf("OUTPUT: ret=%d\n", res);
    free(verify_data);
#endif

out:
    free(pubkey.modulus);
    free(pubkey.pub_expo);
    free(prikey.modulus);
    free(prikey.pub_expo);
    free(prikey.pri_expo);
    free(origin_data);
    free(encrypt_data);
    free(decrypt_data);
    return res;
}

/* Func: show_Asymmetry_ECC_demo
 *
 * SHOW:
 *   - Asymmetry_ECC_keygen: For asymmetric (ECC) key generation
 *   - Asymmetry_ECC_encrypt: For asymmetric (ECC) encrypted data
 *   - Asymmetry_ECC_decrypt: For asymmetric (ECC) decryption of data
 *   - Asymmetry_ECC_sign: For asymmetric (ECC) data signing
 *   - Asymmetry_ECC_verify: For asymmetric (ECC) data signature verification
 */
int show_Asymmetry_ECC_demo()
{
    ECC_prikey prikey;
    ECC_pubkey pubkey;
    std::vector<char> _data = {0x37, 0x33, 0x31, 0x34, 0x35, 0x36};
    std::vector<char> _key;
    size_t data_len = 0, encrypt_len = DATA_MAX_LEN, decrypt_len = DATA_MAX_LEN;
    size_t key_len = 0, alg_enc = 0;
    int enc = 0, func_enc = 0, res = SEC_SUCCESS;
    std::vector<char> v_data = {0x37, 0x33, 0x31, 0x34, 0x35, 0x36};
    // char* verify_data = ( char*)malloc(DATA_MAX_LEN);
    // size_t verify_data_len = 0;
    // unsigned char md[16] = {0};
    // unsigned char md2[16] = {0};

    pubkey.x = (char*)malloc(32);           // SM2_key_len / 8 = 32
    pubkey.y = (char*)malloc(32);
    prikey.x = (char*)malloc(32);
    prikey.y = (char*)malloc(32);
    prikey.pri_val = (char*)malloc(32);
    char* origin_data  = (char*)malloc(DATA_MAX_LEN);
    char* encrypt_data = (char*)malloc(DATA_MAX_LEN);
    char* decrypt_data = (char*)malloc(DATA_MAX_LEN);
    if( nullptr == pubkey.x       ||
        nullptr == pubkey.y       ||
        nullptr == prikey.x       ||
        nullptr == prikey.y       ||
        nullptr == prikey.pri_val ||
        nullptr == origin_data    ||
        nullptr == encrypt_data   ||
        nullptr == decrypt_data){
        printf("malloc fail.\n");
        goto out;
    }

    // set original data
    data_len = _data.size();
    for(unsigned int i = 0; i < data_len; i++) {
        origin_data[i] = _data[i];
    }

    // Asymmetry_ECC_keygen, generate key
    key_len = 256;      // set for SM2
    // encrypt and decrypt
    printf("\n-----\nSHOW Asymmetry_ECC_keygen():\n");
    printf("INPUT: key_len=%d alg_enc=%d\n", key_len, TEE_TYPE_SM2_PKE_KEYPAIR);
    res = Asymmetry_ECC_keygen(key_len, TEE_TYPE_SM2_PKE_KEYPAIR, pubkey, prikey);
    printf("OUTPUT: ret=%d\n", res);

    prikey.x_len = key_len/8;
    prikey.y_len = key_len/8;
    prikey.pri_len = key_len/8;
    pubkey.x_len = key_len/8;
    pubkey.y_len = key_len/8;

    // print key
    printf("prikey:\n");
    printf("prikey.x_len = %zu, prikey.x:\n\t", prikey.x_len);
    for(unsigned int i = 1; i <= prikey.x_len; i++) {
        printf("%02x ", prikey.x[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\nprikey.y_len = %zu, prikey.y:\n\t", prikey.y_len);
    for(unsigned int i = 1; i <= prikey.y_len; i++) {
        printf("%02x ", prikey.y[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\nprikey.pri_len = %zu,  prikey.pri_val:\n\t", prikey.pri_len);
    for(unsigned int i = 1; i <= prikey.pri_len; i++) {
        printf("%02x ", prikey.pri_val[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");
    printf("pubkey:\n");
    printf("pubkey.x_len = %zu, pubkey.x:\n\t", pubkey.x_len);
    for(unsigned int i = 1; i <= pubkey.x_len; i++) {
        printf("%02x ", pubkey.x[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\npubkey.y_len = %zu, pubkey.y:\n\t", pubkey.y_len);
    for(unsigned int i = 1; i <= pubkey.y_len; i++) {
        printf("%02x ", pubkey.y[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // Asymmetry_ECC_encrypt
    encrypt_len = key_len;
    printf("\n-----\nSHOW Asymmetry_ECC_encrypt():\n");
    printf("the original data length is：%zu, data:\n\t", data_len);
    for(unsigned int i = 1; i <= data_len; i++) {
        printf("%02x ", origin_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Asymmetry_ECC_encrypt(origin_data, data_len, encrypt_data, &encrypt_len, pubkey, key_len);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe encrypted data length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // Asymmetry_ECC_decrypt
    decrypt_len = encrypt_len;
    printf("\n-----\nSHOW Asymmetry_ECC_decrypt():\n");
    printf("the encrypted length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Asymmetry_ECC_decrypt(encrypt_data, encrypt_len, decrypt_data, &decrypt_len, prikey, key_len);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe decrypted length is：%zu, data:\n\t", decrypt_len);
    for(unsigned int i = 1; i <= decrypt_len; i++) {
        printf("%02x ", decrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // sign and verify
    res = Asymmetry_ECC_keygen(key_len, TEE_TYPE_SM2_DSA_KEYPAIR, pubkey, prikey);
    printf("OUTPUT: ret=%d\n", res);

    prikey.x_len = key_len/8;
    prikey.y_len = key_len/8;
    prikey.pri_len = key_len/8;
    pubkey.x_len = key_len/8;
    pubkey.y_len = key_len/8;

    // print key
    printf("prikey:\n");
    printf("prikey.x_len = %zu, prikey.x:\n\t", prikey.x_len);
    for(unsigned int i = 1; i <= prikey.x_len; i++) {
        printf("%02x ", prikey.x[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\nprikey.y_len = %zu, prikey.y:\n\t", prikey.y_len);
    for(unsigned int i = 1; i <= prikey.y_len; i++) {
        printf("%02x ", prikey.y[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\nprikey.pri_len = %zu,  prikey.pri_val:\n\t", prikey.pri_len);
    for(unsigned int i = 1; i <= prikey.pri_len; i++) {
        printf("%02x ", prikey.pri_val[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");
    printf("pubkey:\n");
    printf("pubkey.x_len = %zu, pubkey.x:\n\t", pubkey.x_len);
    for(unsigned int i = 1; i <= pubkey.x_len; i++) {
        printf("%02x ", pubkey.x[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\npubkey.y_len = %zu, pubkey.y:\n\t", pubkey.y_len);
    for(unsigned int i = 1; i <= pubkey.y_len; i++) {
        printf("%02x ", pubkey.y[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

#if 0
    // Asymmetry_ECC_sign
    liboa_MD5((unsigned char*)origin_data, data_len, md);
    for(int i = 0; i < 16; i++){
        printf("%02x", md[i]);
    }
    encrypt_len = key_len;
    printf("\n-----\nSHOW Asymmetry_ECC_sign():\n");
    printf("the original data length is：%zu, data:\n\t", data_len);
    for(unsigned int i = 1; i <= data_len; i++) {
        printf("%02x ", origin_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    res = Asymmetry_ECC_sign((char*)md, 16, encrypt_data, &encrypt_len, prikey, key_len);
    printf("OUTPUT: ret=%d\n", res);
    printf("\nthe encrypted data length is：%zu, data:\n\t", encrypt_len);
    for(unsigned int i = 1; i <= encrypt_len; i++) {
        printf("%02x ", encrypt_data[i - 1]);
        if(i % 16 == 0) printf("\n\t");
    }
    printf("\n");

    // Asymmetry_ECC_verify
    memset(verify_data, 0, DATA_MAX_LEN);
    verify_data_len = v_data.size();
    for(unsigned int i = 0; i < verify_data_len; i++) {
        verify_data[i] = v_data[i];
    }
    liboa_MD5((unsigned char*)verify_data, verify_data_len, md2);
    for(int i = 0; i < 16; i++){
        printf("%02x", md2[i]);
    }
    printf("\n-----\nSHOW Asymmetry_ECC_verify():\n");
    res = Asymmetry_ECC_verify((char*)md2, 16, encrypt_data, encrypt_len, pubkey, key_len);
    printf("OUTPUT: ret=%d\n", res);
    free(verify_data);
#endif
out:
    free(pubkey.x);
    free(pubkey.y);
    free(prikey.x);
    free(prikey.y);
    free(prikey.pri_val);
    free(origin_data);
    free(encrypt_data);
    free(decrypt_data);
    return res;
}


int main(int argc, char **argv)
{
    std::cout << "|----------------------------|" << std::endl;
    std::cout << "| libcybersecurity APIs show |" << std::endl;
    std::cout << "|----------------------------|" << std::endl;

    std::cout << "\n--------------------------------------------------------\nR5 APIs:" << std::endl;

    show_libsec_HD_RAND_bytes();

    show_libsec_R5_CRC();

    show_libsec_R5_hash();

    show_libsec_r5_HMAC();

    show_libsec_R5_RSA_EDN();

    // libsec_R5_OTPWriteEncryptedKey(Set related non-test calls, and use them as needed)
    show_libsec_R5_GetTmpEncryptedAESKey_OTPWriteEncryptedKey();

    show_libsec_R5_SM();

    // libsec_R5_SetLifeStage(Set related non-test calls, and use them as needed)
    show_libsec_R5_GetLifeStage_SetLifeStage();

    // libsec_r5_SetUserKey(Set related, as other calls keyIdx)
    show_libsec_r5_SetUserKey();

    // libsec_r5_SetUesrKeyFlag(Set related non-test calls, and use them as needed)
    //show_libsec_r5_SetUesrKeyFlag();

    // libsec_r5_EnableOtpKey(Set related non-test calls, and use them as needed)
    //show_libsec_r5_EnableOtpKey();

    show_libsec_r5_GetKeyStatus();

    show_libsec_r5_GetChipid();

    show_libsec_r5_AES_encrypt();

    show_libsec_R5_ECC_Sign_Verify();

    show_libsec_R5_Get_AntiRollbackInfo();

    std::cout << "\n--------------------------------------------------------\nR5/optee APIs:" << std::endl;

    show_libsec_AES_Encrypt();

    std::cout << "\n--------------------------------------------------------\noptee APIs:" << std::endl;

    show_libsec_inquire_version();

    show_libsec_storage_write_data();

    show_libsec_storage_read_data();

    show_libsec_storage_read_data_ex();

    show_libsec_storage_truncate_data();

    show_libsec_storage_update_data();

    show_libsec_storage_delete_object();

    show_Symmetry_demo();

    show_Asymmetry_RSA_demo();

    show_Asymmetry_ECC_demo();

    return 0;
}
